package com.sentiment.database.dbUtil;

import static com.mongodb.client.model.Filters.and;
import static com.mongodb.client.model.Filters.gt;
import static com.mongodb.client.model.Filters.lt;

import java.util.ArrayList;
import java.util.List;

import org.bson.Document;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mongodb.Block;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
public class DbUtil implements Mongodb{
	private final static Logger LOG = LoggerFactory.getLogger(DbUtil.class);
	private MongoClient client;
	private MongoDatabase db;
	private MongoCollection<Document> collection;
	public MongoCollection<Document> getCollection() {
		return collection;
	}
	public void setCollection(MongoCollection<Document> collection) {
		this.collection = collection;
	}
	public DbUtil() {
		
	}
	/**
	 * 根据页码和每页显示数返回该表中的数据
	 * @param i 页码
	 * @param num 每页显示数
	 * @return
	 */
	
	public List<Document> getPage(Integer i , Integer num){
		FindIterable<Document> it = collection.find();
		MongoCursor<Document> cursor = it.iterator();
		int count = (i-1) * num;
		List<Document> li = new ArrayList<Document>();
		while(cursor.hasNext()){
			if(count > 0 && cursor.hasNext()){
				cursor.next();
				count--;
			}
			else if(li.size() < num && cursor.hasNext()){
				li.add(cursor.next());
			}
			else{
				break;
			}
		}
		return li;
	}
	
	
	public void openConnection(String dbName,String collectionName){
		client = new MongoClient();
		db = client.getDatabase(dbName);
		collection = db.getCollection(collectionName);
	}
	
	public void closeConnection(){
		client.close();
		client = new MongoClient();
	}
	
	
	private Document toDocument(Document t,String[] keys){
		Document doc = new Document();
		for(String key : keys)
			if(key != null)
				doc.append(key, t.get(key));
		return doc;
	}
	
	public boolean insert(Document t) {
		collection.insertOne(t);
		return true;
	}
	
	public ObjectId insertGetId(Document t){
		collection.insertOne(t);
		return t.getObjectId("_id");
	}
	
	public boolean insertNotExist(Document t,String[] keys){
		if(collection.find(toDocument(t,keys)).first() != null)
			return false;
		insert(t);
		return true;
	}
	
	public boolean insertMany(List<Document> list) {
		boolean success = false;
		for(Document t : list)
			if(insert(t))
				success = true;
		return success;
	}
	
	public boolean insertManyNotExist(List<Document> list,List<String[]> keysList){
		boolean success = false;
		if(list.size() != keysList.size()){
			LOG.error("Insert error : The two list size not equal!");
			return success;
		}
		for(int i = 0 ; i < list.size() ; i++)
			if(insertNotExist(list.get(i),keysList.get(i)))
				success = true;
		return success;
	}
	
	public Document query(String id){
		ObjectId oId = new ObjectId(id);
		Document doc = new Document("_id",oId);
		return collection.find(doc).first();
	}
	public Document query(Document t,String[] keys) {
		return collection.find(toDocument(t, keys)).first();
	}
	
	public List<Document> queryMany(Document t,String[] keys) {
		final List<Document> list = new ArrayList<Document>();
		Block<Document> block = new Block<Document>(){
			@Override
			public void apply(Document doc){
				list.add(doc);
			}
		};
		collection.find(toDocument(t, keys)).forEach(block);
		return list;
	}
	
	public List<Document> queryMany(Document start, Document end,String key) {
		final List<Document> list = new ArrayList<Document>();
		Block<Document> block = new Block<Document>() {
			
			@Override
			public void apply(Document doc) {
				list.add(doc);
			}
		};
		switch(key){
		case "date":
		case "login":
		case "logout":
		case "releaseTime":
		case "beginDate":
		case "endDate":
			collection.find(and(gt(key,start.getDate(key)),lt(key,end.getDate(key)))).forEach(block);
			break;
		case "reprint":
		case "pageView":
			collection.find(and(gt(key,start.getInteger(key)),lt(key,end.getInteger(key)))).forEach(block);
			break;
		case "plagiarism":
		case "payment":
		case "sentiment":
			collection.find(and(gt(key,start.getDouble(key)),lt(key,end.getDouble(key)))).forEach(block);
			break;
		default:
			LOG.error("key error : key field is illegal!");
			return null;
		}
		return list;
	}
	public boolean remove(Document t,String[] keys) {
		DeleteResult dr = collection.deleteOne(toDocument(t, keys));
		return dr.getDeletedCount() != 0;
	}
	public long removeMany(Document t,String[] keys){
		DeleteResult dr = collection.deleteMany(toDocument(t,keys));
		return dr.getDeletedCount();
	}
	/**
	 * 
	 * @param name
	 * @param replace
	 * @return
	 */
	public boolean remove(String name, String replace){
		boolean flag = true;
		for(Document doc : collection.find()){
			List<String> list = (List<String>)doc.get(name);
			if(list.contains(replace)){
				List<String> copyList = new ArrayList<String>(list);
				copyList.remove(replace);
				Document newd = new Document();
				newd.append(name, copyList);
				if(!update(doc, new String[]{"_id"}, newd, new String[]{name}))
					flag = false;
			}
		}
		return flag;
	}
	
	/**
	 * 根据对象中的 List 中的一个元素进行查找
	 * @param name List 的名称
	 * @param key List 的一项说
	 * @return 包含该项的整个对象
	 */
	public List<Document> queryByOneinList(String name, String key){
		List<Document> tlist = new ArrayList<>();
		for(Document doc : collection.find()){
			List<String> list = (List<String>)doc.get(name);
			if(list.contains(key)){
				tlist.add(doc);
			}
		}
		return tlist;
	}
	
	public boolean update(Document tOld, String[] oKeys, Document tNew, String[] nKeys) {
		UpdateResult ur = collection.updateOne(toDocument(tOld, oKeys), new Document("$set",toDocument(tNew,nKeys)));
		return ur.getModifiedCount() != 0;
	}
	public long updateMany(Document tOld, String[] oKeys, Document tNew, String[] nKeys){
		UpdateResult ur = collection.updateMany(toDocument(tOld, oKeys), new Document("$set",toDocument(tNew,nKeys)));
		return ur.getModifiedCount();
	}
	
	public long collectionGetCount() {
		return collection.count();
	}
}
